<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>YOLO推理服务 - Web演示</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 20px;
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            border-radius: 15px;
            box-shadow: 0 20px 40px rgba(0,0,0,0.1);
            overflow: hidden;
        }

        .header {
            background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
            color: white;
            padding: 30px;
            text-align: center;
        }

        .header h1 {
            font-size: 2.5em;
            margin-bottom: 10px;
        }

        .header p {
            font-size: 1.2em;
            opacity: 0.9;
        }

        .main-content {
            padding: 40px;
        }

        .server-config-section {
            background: #e8f4fd;
            border-radius: 8px;
            padding: 15px 20px;
            margin-bottom: 20px;
            border: 2px solid #4facfe;
        }

        .server-config-section h2 {
            margin: 0 0 12px 0;
            color: #2c3e50;
            font-size: 18px;
            font-weight: 600;
        }

        .server-controls {
            display: grid;
            grid-template-columns: 1fr auto auto;
            grid-template-rows: auto auto;
            gap: 10px 15px;
            align-items: center;
        }

        .server-url-group {
            grid-column: 1 / -1;
            display: flex;
            align-items: center;
            gap: 15px;
        }

        .server-url-group label {
            font-weight: 600;
            color: #2c3e50;
            min-width: 80px;
            font-size: 14px;
        }

        .server-url-group input {
            flex: 1;
            padding: 8px 12px;
            border: 2px solid #e0e0e0;
            border-radius: 5px;
            font-size: 14px;
        }

        .server-buttons-row {
            grid-column: 1 / -1;
            display: flex;
            align-items: center;
            justify-content: space-between;
        }

        .server-buttons-left {
            display: flex;
            gap: 10px;
        }

        .server-status {
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .test-connection-button {
            background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
            color: white;
            padding: 8px 16px;
            border: none;
            border-radius: 6px;
            font-size: 13px;
            cursor: pointer;
            transition: transform 0.2s ease;
            height: fit-content;
            white-space: nowrap;
        }

        .test-connection-button:hover {
            transform: translateY(-1px);
        }

        .test-connection-button:disabled {
            background: #ccc;
            cursor: not-allowed;
            transform: none;
        }

        .connection-status {
            display: flex;
            align-items: center;
            gap: 8px;
            padding: 10px;
            background: white;
            border-radius: 8px;
            border: 2px solid #e0e0e0;
        }

        .status-indicator {
            font-size: 16px;
        }

        .status-connected {
            border-color: #51cf66;
            background: #f8fff9;
        }

        .status-disconnected {
            border-color: #ff6b6b;
            background: #fff8f8;
        }

        .status-testing {
            border-color: #ffd43b;
            background: #fffef7;
        }

        .status-unknown {
            border-color: #868e96;
            background: #f8f9fa;
        }

        .upload-section {
            background: #f8f9fa;
            border-radius: 10px;
            padding: 30px;
            margin-bottom: 30px;
            text-align: center;
        }

        .file-input-wrapper {
            position: relative;
            display: inline-block;
            margin: 20px 0;
        }

        .file-input {
            display: none;
        }

        .file-input-button {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 15px 30px;
            border-radius: 25px;
            cursor: pointer;
            font-size: 16px;
            transition: transform 0.3s ease;
            display: inline-block;
        }

        .file-input-button:hover {
            transform: translateY(-2px);
        }

        .controls {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 20px;
            margin: 20px 0;
        }

        .control-group {
            display: flex;
            flex-direction: column;
        }

        .control-group label {
            font-weight: 600;
            margin-bottom: 5px;
            color: #333;
        }

        .control-group input, .control-group select {
            padding: 10px;
            border: 2px solid #e0e0e0;
            border-radius: 5px;
            font-size: 14px;
            transition: border-color 0.3s ease;
        }

        .control-group input:focus, .control-group select:focus {
            outline: none;
            border-color: #667eea;
        }

        .model-select-container {
            display: flex;
            gap: 8px;
            align-items: center;
        }

        .model-select-container select {
            flex: 1;
        }

        .hot-swap-btn {
            background: linear-gradient(135deg, #ff6b6b, #ff8e53);
            color: white;
            border: none;
            border-radius: 6px;
            padding: 8px 12px;
            cursor: pointer;
            font-size: 16px;
            transition: all 0.3s ease;
            box-shadow: 0 2px 4px rgba(255, 107, 107, 0.3);
            min-width: 40px;
        }

        .hot-swap-btn:hover {
            background: linear-gradient(135deg, #ff5252, #ff7043);
            transform: translateY(-1px);
            box-shadow: 0 4px 8px rgba(255, 107, 107, 0.4);
        }

        .hot-swap-btn:active {
            transform: translateY(0);
        }

        .hot-swap-btn:disabled {
            background: #ccc;
            cursor: not-allowed;
            transform: none;
            box-shadow: none;
        }

        .detect-button {
            background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 100%);
            color: white;
            padding: 15px 40px;
            border: none;
            border-radius: 25px;
            font-size: 18px;
            cursor: pointer;
            transition: transform 0.3s ease;
            margin: 20px 0;
        }

        .detect-button:hover {
            transform: translateY(-2px);
        }

        .detect-button:disabled {
            background: #ccc;
            cursor: not-allowed;
            transform: none;
        }

        .results-section {
            margin-top: 30px;
        }

        .image-container {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
            gap: 20px;
            margin: 20px 0;
        }

        .image-box {
            background: #f8f9fa;
            border-radius: 10px;
            padding: 20px;
            text-align: center;
        }

        .image-box h3 {
            margin-bottom: 15px;
            color: #333;
        }

        .image-box img {
            max-width: 100%;
            height: auto;
            border-radius: 5px;
            box-shadow: 0 5px 15px rgba(0,0,0,0.1);
        }

        .detection-results {
            background: #f8f9fa;
            border-radius: 10px;
            padding: 20px;
            margin-top: 20px;
        }

        .detection-item {
            background: white;
            border-radius: 5px;
            padding: 15px;
            margin: 10px 0;
            border-left: 4px solid #667eea;
        }

        .detection-item h4 {
            color: #333;
            margin-bottom: 5px;
        }

        .detection-item p {
            color: #666;
            margin: 5px 0;
        }

        .stats {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
            gap: 15px;
            margin: 20px 0;
        }

        .stat-item {
            background: white;
            border-radius: 10px;
            padding: 20px;
            text-align: center;
            box-shadow: 0 5px 15px rgba(0,0,0,0.1);
        }

        .stat-value {
            font-size: 2em;
            font-weight: bold;
            color: #667eea;
        }

        .stat-label {
            color: #666;
            margin-top: 5px;
        }

        .loading {
            display: none;
            text-align: center;
            padding: 20px;
        }

        .spinner {
            border: 4px solid #f3f3f3;
            border-top: 4px solid #667eea;
            border-radius: 50%;
            width: 40px;
            height: 40px;
            animation: spin 1s linear infinite;
            margin: 0 auto 20px;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        .error {
            background: #ff6b6b;
            color: white;
            padding: 15px;
            border-radius: 5px;
            margin: 20px 0;
        }

        .success {
            background: #51cf66;
            color: white;
            padding: 15px;
            border-radius: 5px;
            margin: 20px 0;
        }

        /* 响应式设计 */
        @media (max-width: 768px) {
            .server-url-group {
                flex-direction: column;
                align-items: flex-start;
                gap: 8px;
            }

            .server-url-group label {
                min-width: auto;
            }

            .server-buttons-row {
                flex-direction: column;
                gap: 10px;
                align-items: flex-start;
            }

            .server-buttons-left {
                width: 100%;
                justify-content: flex-start;
            }

            .server-status {
                width: 100%;
            }

            .controls {
                grid-template-columns: 1fr;
            }

            .image-container {
                grid-template-columns: 1fr;
            }

            .stats {
                grid-template-columns: repeat(2, 1fr);
            }

            .container {
                margin: 10px;
            }

            .main-content {
                padding: 20px;
            }

            .header {
                padding: 20px;
            }

            .header h1 {
                font-size: 2em;
            }
        }

        @media (max-width: 480px) {
            .stats {
                grid-template-columns: 1fr;
            }

            .header h1 {
                font-size: 1.8em;
            }

            .header p {
                font-size: 1em;
            }
        }

        /* 标签页样式 */
        .tab-section {
            margin-bottom: 30px;
        }

        .tab-buttons {
            display: flex;
            gap: 10px;
            margin-bottom: 20px;
        }

        .tab-button {
            padding: 12px 24px;
            border: 2px solid #e0e0e0;
            background: white;
            border-radius: 25px;
            cursor: pointer;
            font-size: 16px;
            font-weight: 500;
            transition: all 0.3s ease;
            color: #666;
        }

        .tab-button:hover {
            border-color: #667eea;
            color: #667eea;
            transform: translateY(-2px);
        }

        .tab-button.active {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border-color: #667eea;
        }

        /* RTSP相关样式 */
        .button-group {
            display: flex;
            gap: 15px;
            flex-wrap: wrap;
            align-items: center;
        }

        .status-section, .results-section {
            margin-top: 30px;
            padding: 20px;
            background: #f8f9fa;
            border-radius: 10px;
            border-left: 4px solid #667eea;
        }

        .rtsp-result-item {
            background: white;
            padding: 8px 12px;
            margin: 4px 0;
            border-radius: 6px;
            border-left: 3px solid #4CAF50;
            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
            font-size: 14px;
            display: flex;
            align-items: center;
            justify-content: space-between;
            min-height: 32px;
        }

        .rtsp-result-left {
            display: flex;
            align-items: center;
            gap: 15px;
            flex: 1;
        }

        .rtsp-result-time {
            color: #666;
            font-weight: bold;
            min-width: 80px;
            font-size: 13px;
        }

        .rtsp-result-frame {
            color: #495057;
            min-width: 60px;
            font-size: 13px;
        }

        .rtsp-result-detections {
            color: #2d3748;
            flex: 1;
            font-size: 13px;
        }

        .rtsp-result-performance {
            color: #38a169;
            font-size: 12px;
            min-width: 100px;
            text-align: right;
        }

        .detection-objects {
            display: inline;
        }

        .detection-object {
            background: #e3f2fd;
            padding: 2px 6px;
            border-radius: 3px;
            margin-right: 4px;
            font-size: 12px;
            display: inline-block;
        }

        /* 隐藏旧的样式 */
        .rtsp-result-header {
            display: none;
        }

        .rtsp-detections {
            display: none;
        }

        .rtsp-detection-item {
            display: none;
        }

        .logs-section {
            background: white;
            border-radius: 15px;
            padding: 25px;
            margin-top: 20px;
            box-shadow: 0 4px 15px rgba(0,0,0,0.1);
        }

        .log-entry {
            margin-bottom: 8px;
            padding: 8px 12px;
            border-left: 4px solid #667eea;
            background: #f8f9ff;
            border-radius: 4px;
        }

        .log-timestamp {
            color: #666;
            font-weight: bold;
            margin-right: 10px;
        }

        .log-detection {
            color: #2d3748;
            margin-left: 20px;
        }

        .log-performance {
            color: #38a169;
            font-size: 12px;
            margin-left: 20px;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>🎯 YOLO推理服务</h1>
            <p>基于YOLO 11的高性能目标检测服务</p>
        </div>

        <div class="main-content">
            <!-- 服务器配置区域 -->
            <div class="server-config-section">
                <h2>⚙️ 服务器配置</h2>
                <div class="server-controls">
                    <!-- 第一行：服务器地址输入 -->
                    <div class="server-url-group">
                        <label for="serverUrl">服务器地址:</label>
                        <input type="text" id="serverUrl" value="http://192.168.8.151:8090" placeholder="http://192.168.8.151:8090">
                    </div>

                    <!-- 第二行：按钮和状态 -->
                    <div class="server-buttons-row">
                        <div class="server-buttons-left">
                            <button id="testConnectionBtn" class="test-connection-button" onclick="testConnection()">
                                🔗 测试连接
                            </button>
                            <button class="test-connection-button" onclick="diagnoseCORS()" style="background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%);">
                                🔍 诊断CORS
                            </button>
                        </div>
                        <div class="server-status">
                            <div id="connectionStatus" class="connection-status">
                                <span class="status-indicator" id="statusIndicator">⚪</span>
                                <span id="statusText">未连接</span>
                            </div>
                        </div>
                    </div>
                </div>
            </div>

            <!-- 功能选择标签 -->
            <div class="tab-section">
                <div class="tab-buttons">
                    <button class="tab-button active" onclick="switchTab('image')">📷 图像检测</button>
                    <button class="tab-button" onclick="switchTab('rtsp')">🎥 视频流处理</button>
                </div>
            </div>

            <!-- 图像检测标签页 -->
            <div id="imageSection" class="upload-section">
                <h2>📤 上传图像进行检测</h2>
                <p style="color: #666; margin-bottom: 20px; font-size: 14px;">
                    💡 提示：您可以直接开始检测，无需等待连接测试完成
                </p>
                <div class="file-input-wrapper">
                    <input type="file" id="imageInput" class="file-input" accept="image/*">
                    <label for="imageInput" class="file-input-button">
                        📁 选择图像文件
                    </label>
                </div>

                <div class="controls">
                    <div class="control-group">
                        <label for="modelSelect">模型选择</label>
                        <div class="model-select-container">
                            <select id="modelSelect">
                                <option value="yolo11n">YOLO 11 Nano (快速)</option>
                                <option value="yolo11s">YOLO 11 Small (平衡)</option>
                            </select>
                            <button onclick="hotSwapModel()" class="hot-swap-btn" title="热更新模型（无中断切换）">🔥</button>
                        </div>
                    </div>
                    <div class="control-group">
                        <label for="confidenceThreshold">置信度阈值</label>
                        <input type="number" id="confidenceThreshold" min="0" max="1" step="0.1" value="0.5">
                    </div>
                    <div class="control-group">
                        <label for="iouThreshold">IoU阈值</label>
                        <input type="number" id="iouThreshold" min="0" max="1" step="0.1" value="0.4">
                    </div>
                    <div class="control-group">
                        <label for="maxDetections">最大检测数</label>
                        <input type="number" id="maxDetections" min="1" max="1000" value="100">
                    </div>
                </div>

                <div class="advanced-controls" style="margin-top: 20px;">
                    <details>
                        <summary style="cursor: pointer; font-weight: bold; margin-bottom: 10px;">🔧 高级设置</summary>
                        <div class="controls">
                            <div class="control-group">
                                <label for="classFilter">类别过滤 (用逗号分隔)</label>
                                <input type="text" id="classFilter" placeholder="例如: person,car,dog">
                            </div>
                            <div class="control-group">
                                <label>
                                    <input type="checkbox" id="returnCrops"> 返回裁剪图像
                                </label>
                            </div>
                            <div class="control-group">
                                <button onclick="showPerformanceStats()" class="test-connection-button" style="width: 100%;">
                                    📊 查看性能统计
                                </button>
                            </div>
                        </div>
                    </details>
                </div>

                <button id="detectButton" class="detect-button" onclick="detectObjects()">
                    🔍 开始检测
                </button>
            </div>

            <!-- RTSP视频流处理标签页 -->
            <div id="rtspSection" class="upload-section" style="display: none;">
                <h2>🎥 RTSP视频流处理</h2>
                <p style="color: #666; margin-bottom: 20px; font-size: 14px;">
                    💡 支持RTSP流和本地视频文件，按指定帧率进行实时检测
                </p>

                <div class="controls">
                    <div class="control-group">
                        <label for="rtspUrl">RTSP流地址或视频文件路径</label>
                        <input type="text" id="rtspUrl" placeholder="rtsp://example.com/stream 或 test_video.mp4" value="rtsp://test:!23QweAsd@192.168.8.108/video3">
                    </div>
                    <div class="control-group">
                        <label for="rtspModel">检测模型</label>
                        <select id="rtspModel">
                            <option value="yolo11n">YOLO 11 Nano (快速)</option>
                            <option value="yolo11s">YOLO 11 Small (平衡)</option>
                        </select>
                    </div>
                    <div class="control-group">
                        <label for="rtspConfidence">置信度阈值</label>
                        <input type="number" id="rtspConfidence" min="0" max="1" step="0.1" value="0.5">
                    </div>
                    <div class="control-group">
                        <label for="rtspFps">处理帧率 (每秒处理帧数)</label>
                        <input type="number" id="rtspFps" min="1" max="10" value="1">
                    </div>
                </div>

                <div class="button-group" style="margin: 20px 0;">
                    <button id="startRtspBtn" class="detect-button" onclick="startRtspStream()">
                        🚀 开始处理
                    </button>
                    <button id="stopRtspBtn" class="detect-button" onclick="stopRtspStream()" disabled
                            style="background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 100%);">
                        🛑 停止处理
                    </button>
                    <button id="refreshResultsBtn" class="test-connection-button" onclick="refreshRtspResults()" disabled>
                        🔄 刷新结果
                    </button>
                </div>

                <div id="rtspStatus" class="status-section" style="display: none;">
                    <h3>📊 流状态</h3>
                    <div id="rtspStatusContent"></div>
                </div>

                <div id="rtspResults" class="results-section" style="display: none;">
                    <h3>🎯 实时检测结果</h3>
                    <div id="rtspResultsContent"></div>
                </div>

                <div id="rtspLogs" class="logs-section" style="display: none;">
                    <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
                        <h3>📝 检测日志</h3>
                        <div>
                            <button onclick="clearRtspLogs()" style="
                                padding: 8px 16px;
                                background: #ff6b6b;
                                color: white;
                                border: none;
                                border-radius: 6px;
                                cursor: pointer;
                                margin-right: 10px;
                            ">🗑️ 清空日志</button>
                            <button onclick="exportRtspLogs()" style="
                                padding: 8px 16px;
                                background: #51cf66;
                                color: white;
                                border: none;
                                border-radius: 6px;
                                cursor: pointer;
                            ">💾 导出日志</button>
                        </div>
                    </div>
                    <div id="rtspLogsContent" style="
                        background: #f8f9fa;
                        border: 1px solid #e9ecef;
                        border-radius: 8px;
                        padding: 15px;
                        max-height: 400px;
                        overflow-y: auto;
                        font-family: 'Courier New', monospace;
                        font-size: 14px;
                        line-height: 1.4;
                        white-space: pre-wrap;
                    "></div>
                </div>
            </div>

            <div id="loading" class="loading">
                <div class="spinner"></div>
                <p>正在处理图像，请稍候...</p>
            </div>

            <div id="results" class="results-section" style="display: none;">
                <h2>检测结果</h2>
                
                <div id="stats" class="stats"></div>
                
                <div id="images" class="image-container"></div>
                
                <div id="detections" class="detection-results"></div>
            </div>
        </div>
    </div>

    <script>
        // 全局变量
        let currentApiUrl = 'http://192.168.8.151:8090';
        let connectionStatus = 'disconnected';
        let currentStreamId = null;
        let rtspMonitorInterval = null;
        let rtspLogs = []; // 存储RTSP检测日志
        let lastProcessedResults = new Set(); // 避免重复处理相同结果

        // 页面加载时初始化
        document.addEventListener('DOMContentLoaded', function() {
            // 从localStorage恢复服务器地址
            const savedUrl = localStorage.getItem('yolo_server_url');
            if (savedUrl) {
                document.getElementById('serverUrl').value = savedUrl;
                currentApiUrl = savedUrl;
            }

            // 设置初始连接状态为未测试，但不阻止操作
            updateConnectionStatus('unknown', '点击测试连接或直接开始检测');

            // 监听服务器地址变化
            document.getElementById('serverUrl').addEventListener('change', function() {
                const newUrl = this.value.trim();
                if (newUrl) {
                    currentApiUrl = newUrl;
                    localStorage.setItem('yolo_server_url', newUrl);
                    updateConnectionStatus('unknown', '地址已更改，可测试连接或直接检测');
                }
            });

            // 监听Enter键快速测试连接
            document.getElementById('serverUrl').addEventListener('keypress', function(e) {
                if (e.key === 'Enter') {
                    testConnection();
                }
            });
        });

        // 更新连接状态显示
        function updateConnectionStatus(status, message) {
            connectionStatus = status;
            const indicator = document.getElementById('statusIndicator');
            const text = document.getElementById('statusText');
            const statusDiv = document.getElementById('connectionStatus');

            // 移除所有状态类
            statusDiv.classList.remove('status-connected', 'status-disconnected', 'status-testing');

            switch (status) {
                case 'connected':
                    indicator.textContent = '🟢';
                    text.textContent = message || '连接正常';
                    statusDiv.classList.add('status-connected');
                    break;
                case 'disconnected':
                    indicator.textContent = '🔴';
                    text.textContent = message || '连接失败';
                    statusDiv.classList.add('status-disconnected');
                    break;
                case 'testing':
                    indicator.textContent = '🟡';
                    text.textContent = message || '测试连接中...';
                    statusDiv.classList.add('status-testing');
                    break;
                case 'unknown':
                    indicator.textContent = '⚪';
                    text.textContent = message || '未测试连接';
                    statusDiv.classList.add('status-unknown');
                    break;
                default:
                    indicator.textContent = '⚪';
                    text.textContent = message || '未知状态';
                    statusDiv.classList.add('status-unknown');
            }
        }

        // 测试服务器连接
        async function testConnection() {
            const testBtn = document.getElementById('testConnectionBtn');
            const originalText = testBtn.textContent;
            const serverUrlInput = document.getElementById('serverUrl');

            // 验证URL格式
            const url = serverUrlInput.value.trim();
            if (!url) {
                showError('请输入服务器地址');
                return;
            }

            // 简单的URL格式验证
            try {
                new URL(url);
                currentApiUrl = url;
            } catch (e) {
                showError('请输入有效的服务器地址 (例如: http://localhost:8000)');
                return;
            }

            try {
                testBtn.disabled = true;
                testBtn.textContent = '🔄 测试中...';
                updateConnectionStatus('testing', '正在测试连接...');

                // 设置超时控制
                const controller = new AbortController();
                const timeoutId = setTimeout(() => controller.abort(), 10000); // 10秒超时

                const response = await fetch(`${currentApiUrl}/health`, {
                    method: 'GET',
                    signal: controller.signal,
                    headers: {
                        'Accept': 'application/json',
                        'Content-Type': 'application/json',
                    },
                    mode: 'cors', // 明确指定CORS模式
                    credentials: 'omit' // 不发送凭据
                });

                clearTimeout(timeoutId);

                if (response.ok) {
                    const data = await response.json();
                    const modelCount = data.models?.length || 0;
                    updateConnectionStatus('connected', `连接成功 (${modelCount} 个模型)`);
                    showSuccess(`成功连接到 ${currentApiUrl}`);

                    // 保存成功的URL
                    localStorage.setItem('yolo_server_url', currentApiUrl);

                    // 更新模型列表
                    await updateModelList();
                } else {
                    const errorText = await response.text().catch(() => 'Unknown error');
                    updateConnectionStatus('disconnected', `HTTP ${response.status}: ${response.statusText}`);
                    showError(`连接失败: HTTP ${response.status} - ${errorText}`);
                }
            } catch (error) {
                console.error('连接测试失败:', error);
                let errorMessage = '连接失败';

                if (error.name === 'AbortError') {
                    errorMessage = '连接超时 (10秒)';
                } else if (error.message.includes('Failed to fetch')) {
                    errorMessage = '网络错误：可能是CORS问题、服务器未启动或地址错误。请检查：\n1. 服务器是否正在运行\n2. 地址是否正确\n3. 服务器是否支持跨域请求';
                } else if (error.message.includes('NetworkError')) {
                    errorMessage = '网络连接失败，请检查网络连接和服务器状态';
                } else {
                    errorMessage = error.message;
                }

                updateConnectionStatus('disconnected', errorMessage);
                showError(errorMessage);
            } finally {
                testBtn.disabled = false;
                testBtn.textContent = originalText;
            }
        }

        // 更新模型列表
        async function updateModelList() {
            try {
                const response = await fetch(`${currentApiUrl}/models`);
                if (response.ok) {
                    const data = await response.json();
                    const modelSelect = document.getElementById('modelSelect');

                    // 清空现有选项
                    modelSelect.innerHTML = '';

                    // 添加可用模型
                    if (data.models && data.models.length > 0) {
                        data.models.forEach(model => {
                            const option = document.createElement('option');
                            option.value = model.name;
                            const statusIcon = model.active ? '🔥' : (model.loaded ? '✅' : '⏳');
                            option.textContent = `${model.name.toUpperCase()} (${model.size}) ${statusIcon}`;
                            modelSelect.appendChild(option);
                        });
                    } else {
                        // 添加默认选项
                        const defaultOptions = [
                            { value: 'yolo11n', text: 'YOLO 11 Nano (快速)' },
                            { value: 'yolo11s', text: 'YOLO 11 Small (平衡)' }
                        ];
                        defaultOptions.forEach(opt => {
                            const option = document.createElement('option');
                            option.value = opt.value;
                            option.textContent = opt.text;
                            modelSelect.appendChild(option);
                        });
                    }
                }
            } catch (error) {
                console.error('更新模型列表失败:', error);
            }
        }

        // 热更新模型
        async function hotSwapModel() {
            const modelSelect = document.getElementById('modelSelect');
            const hotSwapBtn = document.querySelector('.hot-swap-btn');
            const selectedModel = modelSelect.value;

            if (!selectedModel) {
                showMessage('请选择要热更新的模型', 'error');
                return;
            }

            // 禁用按钮并显示加载状态
            hotSwapBtn.disabled = true;
            hotSwapBtn.textContent = '🔄';
            hotSwapBtn.title = '正在热更新...';

            try {
                showMessage(`正在热更新模型 ${selectedModel}...`, 'info');

                const startTime = Date.now();
                const response = await fetch(`${currentApiUrl}/models/${selectedModel}/hot-swap`, {
                    method: 'POST'
                });

                const swapTime = Date.now() - startTime;

                if (response.ok) {
                    const result = await response.json();
                    showMessage(
                        `🎉 模型 ${selectedModel} 热更新成功！耗时: ${result.swap_time || (swapTime/1000).toFixed(3)}s`,
                        'success'
                    );

                    // 更新模型列表以反映新状态
                    await updateModelList();

                    // 记录热更新日志
                    addLogEntry(`热更新模型 ${selectedModel} 成功，耗时 ${result.swap_time || (swapTime/1000).toFixed(3)}s`);

                } else {
                    const error = await response.text();
                    showMessage(`热更新失败: ${error}`, 'error');
                    addLogEntry(`热更新模型 ${selectedModel} 失败: ${error}`);
                }

            } catch (error) {
                console.error('热更新失败:', error);
                showMessage(`热更新失败: ${error.message}`, 'error');
                addLogEntry(`热更新模型 ${selectedModel} 失败: ${error.message}`);
            } finally {
                // 恢复按钮状态
                hotSwapBtn.disabled = false;
                hotSwapBtn.textContent = '🔥';
                hotSwapBtn.title = '热更新模型（无中断切换）';
            }
        }

        async function detectObjects() {
            // 移除连接状态检查，允许用户直接尝试检测
            // 如果连接有问题，会在实际请求时显示错误

            const fileInput = document.getElementById('imageInput');
            const file = fileInput.files[0];

            if (!file) {
                showError('请先选择一个图像文件');
                return;
            }

            // 检查文件大小 (限制10MB)
            if (file.size > 10 * 1024 * 1024) {
                showError('文件大小不能超过10MB');
                return;
            }

            // 检查文件类型
            const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/bmp', 'image/webp'];
            if (!allowedTypes.includes(file.type)) {
                showError('不支持的文件格式，请选择 JPEG、PNG、BMP 或 WebP 格式的图像');
                return;
            }

            const formData = new FormData();
            formData.append('file', file);
            formData.append('model_name', document.getElementById('modelSelect').value);
            formData.append('confidence_threshold', document.getElementById('confidenceThreshold').value);
            formData.append('iou_threshold', document.getElementById('iouThreshold').value);
            formData.append('max_detections', document.getElementById('maxDetections').value);
            formData.append('draw_results', 'true');

            // 高级设置
            const returnCrops = document.getElementById('returnCrops').checked;
            formData.append('return_crops', returnCrops.toString());

            const classFilter = document.getElementById('classFilter').value.trim();
            if (classFilter) {
                formData.append('class_filter', classFilter);
            }

            // 显示加载状态
            document.getElementById('loading').style.display = 'block';
            document.getElementById('results').style.display = 'none';
            document.getElementById('detectButton').disabled = true;

            const startTime = Date.now();

            // 添加调试信息
            console.log('🚀 开始检测请求:', {
                url: `${currentApiUrl}/detect/file`,
                fileSize: file.size,
                fileName: file.name,
                fileType: file.type
            });

            // 打印FormData内容（调试用）
            console.log('📋 FormData内容:');
            for (let [key, value] of formData.entries()) {
                if (key === 'file') {
                    console.log(`  ${key}: [File] ${value.name} (${value.size} bytes)`);
                } else {
                    console.log(`  ${key}: ${value}`);
                }
            }

            try {
                const response = await fetch(`${currentApiUrl}/detect/file`, {
                    method: 'POST',
                    body: formData,
                    // 不要设置Content-Type，让浏览器自动设置multipart/form-data边界
                });

                const endTime = Date.now();
                const requestTime = endTime - startTime;

                console.log('📡 收到响应:', {
                    status: response.status,
                    statusText: response.statusText,
                    headers: Object.fromEntries(response.headers.entries()),
                    requestTime: requestTime + 'ms'
                });

                if (!response.ok) {
                    const errorText = await response.text();
                    console.error('❌ 响应错误:', errorText);
                    throw new Error(`HTTP ${response.status}: ${response.statusText} - ${errorText}`);
                }

                const result = await response.json();
                console.log('✅ 解析结果:', result);

                if (result.success) {
                    // 添加请求时间信息
                    result.request_time = requestTime;
                    displayResults(result, file);
                    showSuccess(`检测完成！用时 ${requestTime}ms`);
                } else {
                    showError('检测失败: ' + result.message);
                }
            } catch (error) {
                console.error('检测请求失败:', error);

                let errorMessage = '检测失败: ' + error.message;

                // 根据错误类型给出更友好的提示
                if (error.message.includes('Failed to fetch')) {
                    errorMessage = '无法连接到服务器。可能原因：\n1. 服务器未启动\n2. 地址错误\n3. CORS跨域问题\n请检查服务器状态和地址设置';
                    updateConnectionStatus('disconnected', '连接失败');
                } else if (error.message.includes('NetworkError')) {
                    errorMessage = '网络连接失败，请检查网络连接和服务器状态';
                    updateConnectionStatus('disconnected', '网络错误');
                } else if (error.message.includes('timeout')) {
                    errorMessage = '请求超时，服务器可能正在处理其他请求，请稍后重试';
                } else if (error.message.includes('HTTP 404')) {
                    errorMessage = '检测接口不存在，请检查服务器版本是否正确';
                } else if (error.message.includes('HTTP 500')) {
                    errorMessage = '服务器内部错误，请检查服务器日志';
                }

                showError(errorMessage);
            } finally {
                document.getElementById('loading').style.display = 'none';
                document.getElementById('detectButton').disabled = false;
            }
        }
        
        function displayResults(result, originalFile) {
            // 显示统计信息
            const statsHtml = `
                <div class="stat-item">
                    <div class="stat-value">${result.results.length}</div>
                    <div class="stat-label">检测到的物体</div>
                </div>
                <div class="stat-item">
                    <div class="stat-value">${(result.inference_time * 1000).toFixed(0)}ms</div>
                    <div class="stat-label">推理时间</div>
                </div>
                <div class="stat-item">
                    <div class="stat-value">${(result.total_time * 1000).toFixed(0)}ms</div>
                    <div class="stat-label">总处理时间</div>
                </div>
                <div class="stat-item">
                    <div class="stat-value">${result.request_time || 0}ms</div>
                    <div class="stat-label">网络请求时间</div>
                </div>
                <div class="stat-item">
                    <div class="stat-value">${result.image_size[0]}×${result.image_size[1]}</div>
                    <div class="stat-label">图像尺寸</div>
                </div>
                <div class="stat-item">
                    <div class="stat-value">${result.model_name}</div>
                    <div class="stat-label">使用模型</div>
                </div>
            `;
            document.getElementById('stats').innerHTML = statsHtml;
            
            // 显示图像
            const originalImageUrl = URL.createObjectURL(originalFile);
            let imagesHtml = `
                <div class="image-box">
                    <h3>原始图像</h3>
                    <img src="${originalImageUrl}" alt="原始图像">
                </div>
            `;
            
            if (result.result_image) {
                imagesHtml += `
                    <div class="image-box">
                        <h3>检测结果</h3>
                        <img src="data:image/jpeg;base64,${result.result_image}" alt="检测结果">
                    </div>
                `;
            }
            document.getElementById('images').innerHTML = imagesHtml;
            
            // 显示检测详情
            let detectionsHtml = '<h3>检测详情</h3>';
            if (result.results.length === 0) {
                detectionsHtml += '<p>未检测到任何物体</p>';
            } else {
                result.results.forEach((detection, index) => {
                    detectionsHtml += `
                        <div class="detection-item">
                            <h4>${detection.class_name}</h4>
                            <p><strong>置信度:</strong> ${(detection.confidence * 100).toFixed(1)}%</p>
                            <p><strong>位置:</strong> (${detection.bbox[0].toFixed(0)}, ${detection.bbox[1].toFixed(0)}) - (${detection.bbox[2].toFixed(0)}, ${detection.bbox[3].toFixed(0)})</p>
                            <p><strong>面积:</strong> ${detection.area.toFixed(0)} 像素</p>
                        </div>
                    `;
                });
            }
            document.getElementById('detections').innerHTML = detectionsHtml;
            
            document.getElementById('results').style.display = 'block';
        }
        
        function showError(message) {
            showNotification(message, 'error');
        }

        function showSuccess(message) {
            showNotification(message, 'success');
        }

        function showNotification(message, type = 'info') {
            // 移除现有通知
            const existingNotifications = document.querySelectorAll('.notification');
            existingNotifications.forEach(n => n.remove());

            const notificationDiv = document.createElement('div');
            notificationDiv.className = `notification ${type}`;

            const icon = type === 'error' ? '❌' : type === 'success' ? '✅' : 'ℹ️';
            notificationDiv.innerHTML = `
                <span class="notification-icon">${icon}</span>
                <span class="notification-message">${message}</span>
                <button class="notification-close" onclick="this.parentElement.remove()">×</button>
            `;

            // 添加通知样式
            notificationDiv.style.cssText = `
                position: fixed;
                top: 20px;
                right: 20px;
                background: ${type === 'error' ? '#ff6b6b' : type === 'success' ? '#51cf66' : '#4facfe'};
                color: white;
                padding: 15px 20px;
                border-radius: 8px;
                box-shadow: 0 4px 12px rgba(0,0,0,0.15);
                z-index: 1000;
                display: flex;
                align-items: center;
                gap: 10px;
                max-width: 400px;
                animation: slideIn 0.3s ease-out;
            `;

            document.body.appendChild(notificationDiv);

            // 自动移除
            setTimeout(() => {
                if (notificationDiv.parentElement) {
                    notificationDiv.style.animation = 'slideOut 0.3s ease-in';
                    setTimeout(() => notificationDiv.remove(), 300);
                }
            }, 5000);
        }

        // 添加动画样式
        const style = document.createElement('style');
        style.textContent = `
            @keyframes slideIn {
                from { transform: translateX(100%); opacity: 0; }
                to { transform: translateX(0); opacity: 1; }
            }
            @keyframes slideOut {
                from { transform: translateX(0); opacity: 1; }
                to { transform: translateX(100%); opacity: 0; }
            }
            .notification-close {
                background: none;
                border: none;
                color: white;
                font-size: 18px;
                cursor: pointer;
                padding: 0;
                margin-left: auto;
            }
            .notification-close:hover {
                opacity: 0.7;
            }
        `;
        document.head.appendChild(style);
        
        // 显示性能统计
        async function showPerformanceStats() {
            // 移除连接状态检查，直接尝试获取性能统计

            try {
                const response = await fetch(`${currentApiUrl}/performance`);
                if (response.ok) {
                    const data = await response.json();
                    displayPerformanceModal(data);
                } else {
                    showError('获取性能统计失败');
                }
            } catch (error) {
                showError('获取性能统计失败: ' + error.message);
            }
        }

        // 显示性能统计模态框
        function displayPerformanceModal(data) {
            const modal = document.createElement('div');
            modal.style.cssText = `
                position: fixed;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background: rgba(0,0,0,0.5);
                display: flex;
                justify-content: center;
                align-items: center;
                z-index: 2000;
            `;

            const content = document.createElement('div');
            content.style.cssText = `
                background: white;
                border-radius: 15px;
                padding: 30px;
                max-width: 600px;
                max-height: 80vh;
                overflow-y: auto;
                position: relative;
            `;

            const global = data.global || {};
            const models = data.models || {};

            content.innerHTML = `
                <button onclick="this.closest('.modal').remove()" style="
                    position: absolute;
                    top: 15px;
                    right: 15px;
                    background: none;
                    border: none;
                    font-size: 24px;
                    cursor: pointer;
                ">×</button>

                <h2 style="margin-bottom: 20px; color: #333;">📊 性能统计</h2>

                <div style="margin-bottom: 20px;">
                    <h3 style="color: #667eea;">全局统计</h3>
                    <div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin: 10px 0;">
                        <div style="background: #f8f9fa; padding: 10px; border-radius: 5px;">
                            <strong>总请求数:</strong> ${global.total_requests || 0}
                        </div>
                        <div style="background: #f8f9fa; padding: 10px; border-radius: 5px;">
                            <strong>错误数:</strong> ${global.total_errors || 0}
                        </div>
                        <div style="background: #f8f9fa; padding: 10px; border-radius: 5px;">
                            <strong>当前速率:</strong> ${(global.current_rate || 0).toFixed(2)} req/s
                        </div>
                        <div style="background: #f8f9fa; padding: 10px; border-radius: 5px;">
                            <strong>运行时间:</strong> ${(global.uptime_hours || 0).toFixed(1)} 小时
                        </div>
                    </div>
                </div>

                <div>
                    <h3 style="color: #667eea;">模型统计</h3>
                    ${Object.keys(models).map(modelName => {
                        const model = models[modelName];
                        return `
                            <div style="background: #f8f9fa; padding: 15px; margin: 10px 0; border-radius: 8px;">
                                <h4 style="margin: 0 0 10px 0; color: #333;">${modelName.toUpperCase()}</h4>
                                <div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; font-size: 14px;">
                                    <div><strong>请求数:</strong> ${model.total_requests || 0}</div>
                                    <div><strong>成功率:</strong> ${((model.success_rate || 0) * 100).toFixed(1)}%</div>
                                    <div><strong>平均推理时间:</strong> ${((model.avg_inference_time || 0) * 1000).toFixed(1)}ms</div>
                                    <div><strong>最近平均时间:</strong> ${((model.recent_avg_inference_time || 0) * 1000).toFixed(1)}ms</div>
                                </div>
                            </div>
                        `;
                    }).join('')}
                </div>
            `;

            modal.className = 'modal';
            modal.appendChild(content);
            document.body.appendChild(modal);

            // 点击背景关闭
            modal.addEventListener('click', function(e) {
                if (e.target === modal) {
                    modal.remove();
                }
            });
        }

        // CORS诊断功能
        async function diagnoseCORS() {
            const serverUrl = document.getElementById('serverUrl').value.trim();
            if (!serverUrl) {
                showError('请先输入服务器地址');
                return;
            }

            const diagnosticResults = [];

            try {
                // 1. 测试基本连接
                diagnosticResults.push('🔍 开始CORS诊断...\n');

                // 2. 测试预检请求
                diagnosticResults.push('1️⃣ 测试预检请求 (OPTIONS)...');
                try {
                    const optionsResponse = await fetch(`${serverUrl}/health`, {
                        method: 'OPTIONS',
                        headers: {
                            'Origin': window.location.origin,
                            'Access-Control-Request-Method': 'GET',
                            'Access-Control-Request-Headers': 'Content-Type'
                        }
                    });
                    diagnosticResults.push(`   ✅ 预检请求状态: ${optionsResponse.status}`);

                    // 检查CORS头部
                    const corsHeaders = [];
                    optionsResponse.headers.forEach((value, key) => {
                        if (key.toLowerCase().includes('access-control')) {
                            corsHeaders.push(`   📋 ${key}: ${value}`);
                        }
                    });

                    if (corsHeaders.length > 0) {
                        diagnosticResults.push('   ✅ 发现CORS头部:');
                        diagnosticResults.push(...corsHeaders);
                    } else {
                        diagnosticResults.push('   ❌ 未发现CORS头部 - 服务器可能需要重启');
                    }
                } catch (e) {
                    diagnosticResults.push(`   ❌ 预检请求失败: ${e.message}`);
                }

                // 3. 测试实际GET请求
                diagnosticResults.push('\n2️⃣ 测试实际GET请求...');
                try {
                    const getResponse = await fetch(`${serverUrl}/health`, {
                        method: 'GET',
                        headers: {
                            'Origin': window.location.origin
                        }
                    });
                    diagnosticResults.push(`   ✅ GET请求状态: ${getResponse.status}`);

                    if (getResponse.ok) {
                        const data = await getResponse.json();
                        diagnosticResults.push(`   ✅ 响应数据: ${data.status} (${data.models?.length || 0} 个模型)`);
                    }
                } catch (e) {
                    diagnosticResults.push(`   ❌ GET请求失败: ${e.message}`);
                    if (e.message.includes('Failed to fetch')) {
                        diagnosticResults.push('   💡 这通常是CORS问题，请重启服务器');
                    }
                }

                // 4. 建议
                diagnosticResults.push('\n📋 诊断建议:');
                diagnosticResults.push('• 如果没有CORS头部，请重启YOLO推理服务器');
                diagnosticResults.push('• 确认服务器地址正确');
                diagnosticResults.push('• 检查服务器是否正在运行');
                diagnosticResults.push('• 查看浏览器控制台的详细错误信息');

            } catch (error) {
                diagnosticResults.push(`❌ 诊断过程出错: ${error.message}`);
            }

            // 显示诊断结果
            showDiagnosticModal(diagnosticResults.join('\n'));
        }

        // 显示诊断结果模态框
        function showDiagnosticModal(results) {
            const modal = document.createElement('div');
            modal.style.cssText = `
                position: fixed;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background: rgba(0,0,0,0.5);
                display: flex;
                justify-content: center;
                align-items: center;
                z-index: 2000;
            `;

            const content = document.createElement('div');
            content.style.cssText = `
                background: white;
                border-radius: 15px;
                padding: 30px;
                max-width: 700px;
                max-height: 80vh;
                overflow-y: auto;
                position: relative;
                font-family: monospace;
            `;

            content.innerHTML = `
                <button onclick="this.closest('.modal').remove()" style="
                    position: absolute;
                    top: 15px;
                    right: 15px;
                    background: none;
                    border: none;
                    font-size: 24px;
                    cursor: pointer;
                ">×</button>

                <h2 style="margin-bottom: 20px; color: #333;">🔍 CORS诊断结果</h2>

                <pre style="
                    background: #f8f9fa;
                    padding: 20px;
                    border-radius: 8px;
                    white-space: pre-wrap;
                    font-size: 14px;
                    line-height: 1.5;
                    margin: 0;
                ">${results}</pre>

                <div style="margin-top: 20px; text-align: center;">
                    <button onclick="this.closest('.modal').remove()" style="
                        background: #4facfe;
                        color: white;
                        padding: 10px 20px;
                        border: none;
                        border-radius: 5px;
                        cursor: pointer;
                    ">关闭</button>
                </div>
            `;

            modal.className = 'modal';
            modal.appendChild(content);
            document.body.appendChild(modal);

            // 点击背景关闭
            modal.addEventListener('click', function(e) {
                if (e.target === modal) {
                    modal.remove();
                }
            });
        }

        // 文件选择时显示文件名
        document.getElementById('imageInput').addEventListener('change', function(e) {
            const fileName = e.target.files[0]?.name;
            if (fileName) {
                document.querySelector('.file-input-button').textContent = `📁 ${fileName}`;
            }
        });

        // 标签页切换功能
        function switchTab(tabName) {
            // 更新标签按钮状态
            document.querySelectorAll('.tab-button').forEach(btn => {
                btn.classList.remove('active');
            });
            event.target.classList.add('active');

            // 显示/隐藏对应的内容区域
            const imageSection = document.getElementById('imageSection');
            const rtspSection = document.getElementById('rtspSection');

            if (tabName === 'image') {
                imageSection.style.display = 'block';
                rtspSection.style.display = 'none';
            } else if (tabName === 'rtsp') {
                imageSection.style.display = 'none';
                rtspSection.style.display = 'block';
            }
        }

        // RTSP流处理功能
        async function startRtspStream() {
            const rtspUrl = document.getElementById('rtspUrl').value.trim();
            const model = document.getElementById('rtspModel').value;
            const confidence = parseFloat(document.getElementById('rtspConfidence').value);
            const fps = parseInt(document.getElementById('rtspFps').value);

            if (!rtspUrl) {
                showError('请输入RTSP流地址或视频文件路径');
                return;
            }

            const startBtn = document.getElementById('startRtspBtn');
            const stopBtn = document.getElementById('stopRtspBtn');
            const refreshBtn = document.getElementById('refreshResultsBtn');

            try {
                startBtn.disabled = true;
                startBtn.textContent = '🚀 启动中...';

                console.log('启动RTSP流处理:', {
                    rtspUrl, model, confidence, fps
                });

                const formData = new FormData();
                formData.append('rtsp_url', rtspUrl);
                formData.append('model_name', model);
                formData.append('confidence_threshold', confidence);
                formData.append('fps_target', fps);

                const response = await fetch(`${currentApiUrl}/rtsp/start`, {
                    method: 'POST',
                    body: formData
                });

                if (!response.ok) {
                    throw new Error(`HTTP ${response.status}: ${response.statusText}`);
                }

                const result = await response.json();

                if (result.success) {
                    currentStreamId = result.stream_id;
                    showSuccess(`RTSP流处理已启动！Stream ID: ${currentStreamId}`);

                    // 更新按钮状态
                    startBtn.disabled = true;
                    stopBtn.disabled = false;
                    refreshBtn.disabled = false;

                    // 显示状态区域
                    document.getElementById('rtspStatus').style.display = 'block';
                    document.getElementById('rtspResults').style.display = 'block';
                    document.getElementById('rtspLogs').style.display = 'block';

                    // 开始监控
                    startRtspMonitoring();
                } else {
                    throw new Error(result.message || '启动失败');
                }

            } catch (error) {
                console.error('启动RTSP流失败:', error);
                showError(`启动RTSP流失败: ${error.message}`);
            } finally {
                startBtn.disabled = false;
                startBtn.textContent = '🚀 开始处理';
            }
        }

        async function stopRtspStream() {
            if (!currentStreamId) {
                showError('没有活跃的流需要停止');
                return;
            }

            const stopBtn = document.getElementById('stopRtspBtn');
            const startBtn = document.getElementById('startRtspBtn');
            const refreshBtn = document.getElementById('refreshResultsBtn');

            try {
                stopBtn.disabled = true;
                stopBtn.textContent = '🛑 停止中...';

                const response = await fetch(`${currentApiUrl}/rtsp/stop/${currentStreamId}`, {
                    method: 'POST'
                });

                if (!response.ok) {
                    throw new Error(`HTTP ${response.status}: ${response.statusText}`);
                }

                const result = await response.json();

                if (result.success) {
                    showSuccess('RTSP流处理已停止');

                    // 停止监控
                    stopRtspMonitoring();

                    // 重置状态
                    currentStreamId = null;
                    startBtn.disabled = false;
                    stopBtn.disabled = true;
                    refreshBtn.disabled = true;

                    // 隐藏状态区域
                    document.getElementById('rtspStatus').style.display = 'none';
                    document.getElementById('rtspResults').style.display = 'none';
                    document.getElementById('rtspLogs').style.display = 'none';
                } else {
                    throw new Error(result.message || '停止失败');
                }

            } catch (error) {
                console.error('停止RTSP流失败:', error);
                showError(`停止RTSP流失败: ${error.message}`);
            } finally {
                stopBtn.disabled = false;
                stopBtn.textContent = '🛑 停止处理';
            }
        }

        function startRtspMonitoring() {
            if (rtspMonitorInterval) {
                clearInterval(rtspMonitorInterval);
            }

            // 每5秒刷新一次结果
            rtspMonitorInterval = setInterval(() => {
                refreshRtspResults();
                updateRtspStatus();
            }, 5000);

            // 立即执行一次
            refreshRtspResults();
            updateRtspStatus();
        }

        function stopRtspMonitoring() {
            if (rtspMonitorInterval) {
                clearInterval(rtspMonitorInterval);
                rtspMonitorInterval = null;
            }
        }

        async function refreshRtspResults() {
            if (!currentStreamId) return;

            try {
                const response = await fetch(`${currentApiUrl}/rtsp/results/${currentStreamId}?max_results=10`);
                if (!response.ok) return;

                const result = await response.json();
                if (result.success && result.results.length > 0) {
                    displayRtspResults(result.results);
                }
            } catch (error) {
                console.error('获取RTSP结果失败:', error);
            }
        }

        async function updateRtspStatus() {
            if (!currentStreamId) return;

            try {
                const response = await fetch(`${currentApiUrl}/rtsp/stream/${currentStreamId}/status`);
                if (!response.ok) return;

                const result = await response.json();
                if (result.success) {
                    displayRtspStatus(result.status);
                }
            } catch (error) {
                console.error('获取RTSP状态失败:', error);
            }
        }

        function displayRtspStatus(status) {
            const statusContent = document.getElementById('rtspStatusContent');
            const info = status.info;

            statusContent.innerHTML = `
                <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px;">
                    <div><strong>流状态:</strong> ${status.is_active ? '🟢 活跃' : '🔴 停止'}</div>
                    <div><strong>队列大小:</strong> ${status.queue_size}</div>
                    <div><strong>模型:</strong> ${info.model_name}</div>
                    <div><strong>置信度:</strong> ${info.confidence_threshold}</div>
                    <div><strong>处理FPS:</strong> ${(1 / info.frame_interval).toFixed(1)}</div>
                    <div><strong>视频FPS:</strong> ${info.fps?.toFixed(1) || 'N/A'}</div>
                    <div><strong>分辨率:</strong> ${info.width}x${info.height}</div>
                </div>
            `;
        }

        function displayRtspResults(results) {
            const resultsContent = document.getElementById('rtspResultsContent');

            // 处理新结果并添加到日志
            results.forEach(result => {
                const resultKey = `${result.timestamp}_${result.frame_number}`;
                if (!lastProcessedResults.has(resultKey)) {
                    lastProcessedResults.add(resultKey);
                    addToRtspLogs(result);
                }
            });

            const html = results.map(result => {
                const timestamp = new Date(result.timestamp * 1000).toLocaleTimeString();
                const detections = result.results || [];

                // 格式化检测对象
                let detectionsText = '';
                if (detections.length === 0) {
                    detectionsText = '<span style="color: #999;">无检测对象</span>';
                } else {
                    const objectsText = detections.slice(0, 4).map(det =>
                        `<span class="detection-object">${det.class_name} ${(det.confidence * 100).toFixed(0)}%</span>`
                    ).join('');
                    const moreText = detections.length > 4 ? ` <span style="color: #666;">+${detections.length - 4}个</span>` : '';
                    detectionsText = objectsText + moreText;
                }

                return `
                    <div class="rtsp-result-item">
                        <div class="rtsp-result-left">
                            <span class="rtsp-result-time">${timestamp}</span>
                            <span class="rtsp-result-frame">帧${result.frame_number}</span>
                            <span class="rtsp-result-detections">${detectionsText}</span>
                        </div>
                        <span class="rtsp-result-performance">推理${(result.inference_time * 1000).toFixed(0)}ms</span>
                    </div>
                `;
            }).join('');

            resultsContent.innerHTML = html || '<p style="text-align: center; color: #999; padding: 20px;">暂无检测结果</p>';
        }

        function addToRtspLogs(result) {
            const timestamp = new Date(result.timestamp * 1000);
            const timeStr = timestamp.toLocaleString();
            const detections = result.results || [];

            // 创建日志条目
            const logEntry = {
                timestamp: result.timestamp,
                timeStr: timeStr,
                frameNumber: result.frame_number,
                detections: detections,
                inferenceTime: result.inference_time,
                totalTime: result.total_time,
                processingInterval: result.processing_interval
            };

            // 添加到日志数组（保持最新的1000条记录）
            rtspLogs.unshift(logEntry);
            if (rtspLogs.length > 1000) {
                rtspLogs = rtspLogs.slice(0, 1000);
            }

            // 更新日志显示
            updateRtspLogsDisplay();
        }

        function updateRtspLogsDisplay() {
            const logsContent = document.getElementById('rtspLogsContent');

            const logsHtml = rtspLogs.slice(0, 50).map(log => {
                const detectionsText = log.detections.length > 0
                    ? log.detections.map(det => `${det.class_name}(${(det.confidence * 100).toFixed(1)}%)`).join(', ')
                    : '无检测对象';

                return `<div class="log-entry">
                    <span class="log-timestamp">[${log.timeStr}]</span>
                    <span>帧${log.frameNumber}: ${detectionsText}</span>
                    <div class="log-performance">推理时间: ${(log.inferenceTime * 1000).toFixed(0)}ms | 总时间: ${(log.totalTime * 1000).toFixed(0)}ms | 处理间隔: ${log.processingInterval.toFixed(2)}s</div>
                </div>`;
            }).join('');

            logsContent.innerHTML = logsHtml || '<div style="color: #666; text-align: center; padding: 20px;">暂无日志记录</div>';

            // 自动滚动到顶部显示最新日志
            logsContent.scrollTop = 0;
        }

        function clearRtspLogs() {
            if (confirm('确定要清空所有日志记录吗？')) {
                rtspLogs = [];
                lastProcessedResults.clear();
                updateRtspLogsDisplay();
                showSuccess('日志已清空');
            }
        }

        function exportRtspLogs() {
            if (rtspLogs.length === 0) {
                showError('没有日志可以导出');
                return;
            }

            const csvContent = [
                '时间,帧号,检测对象数,检测结果,推理时间(ms),总时间(ms),处理间隔(s)',
                ...rtspLogs.map(log => {
                    const detectionsText = log.detections.map(det =>
                        `${det.class_name}(${(det.confidence * 100).toFixed(1)}%)`
                    ).join(';');

                    return [
                        log.timeStr,
                        log.frameNumber,
                        log.detections.length,
                        `"${detectionsText}"`,
                        (log.inferenceTime * 1000).toFixed(0),
                        (log.totalTime * 1000).toFixed(0),
                        log.processingInterval.toFixed(2)
                    ].join(',');
                })
            ].join('\n');

            const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
            const link = document.createElement('a');
            const url = URL.createObjectURL(blob);
            link.setAttribute('href', url);
            link.setAttribute('download', `rtsp_logs_${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.csv`);
            link.style.visibility = 'hidden';
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);

            showSuccess(`已导出 ${rtspLogs.length} 条日志记录`);
        }
    </script>
</body>
</html>
